#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
#include "Tool.hpp"
#include "InetAddr.hpp"
using namespace LogModel;
int ndefault = 5;
class Socket
{
public:
    virtual void ListenSocket() = 0;
    virtual void Bind(uint16_t port) = 0;
    virtual void Listen(int n) = 0;
    virtual int Accept(InetAddr *client) = 0;
    virtual void Close() = 0;
    virtual int Recv(std::string *josn_str) = 0;
    virtual int Send(std::string &massage) = 0;
    virtual int Connect(std::string &server_ip, uint16_t port) = 0;
    virtual int Fd()=0;
    void BuildTcpSocketServer(uint16_t port, int n = ndefault)
    {
        ListenSocket();
        Bind(port);
        Listen(n);
    }
    void BuildTcpSocketClient()
    {
        ListenSocket();
    }
};

class TcpSocket : public Socket
{
public:
    TcpSocket() : _sockfd(-1)
    {
    }

    TcpSocket(int fd) : _sockfd(fd)
    {
    }

    ~TcpSocket()
    {
    }

    void ListenSocket() override
    {
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket error";
            exit(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket success";
    }

    void Bind(uint16_t port) override
    {
        InetAddr server(port);
        int n = bind(_sockfd, server.Addr(), server.Getsize());
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            exit(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success";
    }

    void Listen(int n) override
    {
        int m = listen(_sockfd, n);
        if (m < 0)
        {
            LOG(LogLevel::FATAL) << "listen error";
            exit(LISTEN_ERR);
        }
        LOG(LogLevel::INFO) << "listen success";
    }

    int Accept(InetAddr *client) override
    {
        sockaddr_in peer;
        socklen_t len = sizeof(peer);
        int fd = accept(_sockfd, CONT(peer), &len);
        if (fd < 0)
        {
            LOG(LogLevel::ERROR) << "accept warning ...";
            return -1;
        }
        client->SetAddr(peer);
        // 直接返回一个指向该新类的指针，该类的sockfd指向的是与客户端交互的文件
        return fd;
    }
    void Close()
    {
        if (_sockfd > 0)
            close(_sockfd);
    }
    int Recv(std::string *josn_str) override
    {
        char buff[1024];
        int n = recv(_sockfd, buff, sizeof(buff) - 1, 0);
        if (n)
        {
            buff[n] = 0;
            *josn_str += buff;
        }
        return n;
    }
    int Fd(){return _sockfd;}
    int Send(std::string &massage)
    {
        return send(_sockfd, massage.c_str(), massage.size(), 0);
    }
    int Connect(std::string &server_ip, uint16_t port) override
    {
        InetAddr server(server_ip, port);
        return connect(_sockfd, server.Addr(), server.Getsize());
    }

private:
    int _sockfd;
};